package com.weblog.weblog.common.aspect;

import com.weblog.weblog.common.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author gc
 * @class_name ApiOperationLogAspect
 * @date 2023年09月13日 17:07
 */

@Aspect
@Component
@Slf4j
public class ApiOperationLogAspect {
    /**使用自定义@ApiOperationLog 注解为切点，添加@ApiOperationLog 的方法执行环绕代码**/
    @Pointcut("@annotation(com.weblog.weblog.common.aspect.ApiOperationLog)")
    public void apiOperationLog(){}

    /**
     * 环绕代码
     * @author gc
     * @date 2023/9/13 17:10
     * @param joinPoint 切点
     * @return null
     */
    @Around("apiOperationLog()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
        try {
            //MDC
            MDC.put("traceId", UUID.randomUUID().toString());

            //请求开始时间
            long startTime = System.currentTimeMillis();

            //请求类及方法
            String className = joinPoint.getTarget().getClass().getSimpleName();
            String methodName = joinPoint.getSignature().getName();

            //入参
            Object[] args = joinPoint.getArgs();

            //入参转json
            String argsJsonStr = Arrays.stream(args).map(toJsonStr()).collect(Collectors.joining(", "));

            // 功能描述信息
            String description = getApiOperationLogDescription(joinPoint);

            //打印请求相关参数
            log.info("====== 请求开始: [{}], 入参: {}, 请求类: {}, 请求方法: {} =================================== ",
                    description,argsJsonStr,className,methodName);

            //执行切点方法
            Object result = joinPoint.proceed();

            //执行耗时
            long executionTime = System.currentTimeMillis() - startTime;

            //打印相关信息
            log.info("====== 请求结束: [{}], 耗时: {}ms, 出参: {} =================================== ",
                    description,executionTime,JsonUtil.toJsonString(result));

            return result;
        } finally {
            MDC.clear();
        }


    }
    /*
     * 获取描述信息
     * @author gc
     * @date 2023/9/13 17:26
     * @param null
     * @return null
     */

    private String getApiOperationLogDescription(ProceedingJoinPoint joinPoint) {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();

        Method method = signature.getMethod();

        ApiOperationLog annotation = method.getAnnotation(ApiOperationLog.class);

        return annotation.description();
    }


    /**
     * 转 JSON 字符串
     */
    private Function<Object, String> toJsonStr() {
        return JsonUtil::toJsonString;
    }
}
